<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');

/**
 * GeSHi Plugin for CodeIgniter
 *
 * This is a simple and efficient plugin for CodeIgniter to implement advanced, flexible
 * code-highlighting for CodeIgniter using the popular GeSHi Syntax Highlighter.
 * 
 * This file should be named "geshi_hook.php" (all lower-case), and go into your "application/hooks"
 * directory.  For more information and installation instructions, refer to the link below.
 * 
 * @author	Casey McLaughlin
 * @link		http://www.caseyamcl.com/resources/geshiForCI
 * @version 1.0
 */
class Geshi_hook
{
	var $ci;
	var $line_numbers_on;
	
  // ------------------------------------------------------------------------
	
  /**
   * Constructor
   *
   * @access public
   * @return Geshi_hook
   */
	function Geshi_hook()
	{
	  //Check PHP version
	  if (phpversion() < 5.0)
	    throw new Exception('The Geshi_Hook plugin for CodeIgniter requires PHP v5.0 or newer!');
	  
	  //Get access to CI library
		$this->ci =& get_instance();
		
		//Attempt to include the GeSHi library
		if ( ! @include(dirname(__FILE__) . '/geshi/geshi.php'))
		  throw new Exception('Could not load the GeSHi file, which is supposed to be located at hooks/geshi/geshi.php in your application folder.');
		  
		//Ensure the GeSHi class actually exists
		if ( ! $test = @new GeSHi('test1234', 'php'))
		  throw new Exception("Could not load the geshi class while trying to load the geshi_hook plugin for CodeIgniter.");

		//If line numbers is turned on as a config item, set that to true in this class
		if ($this->ci->config->item('geshi_line_numbers') === TRUE)
			$this->line_numbers_on = TRUE;
		else
			$this->line_numbers_on = FALSE;
		  
		//If made it here with no exceptions, good to go!
	}

  // ------------------------------------------------------------------------	
	
  /**
   * Run the GeSHi filter on the CodeIgniter output
   *
   * This function should be called only as a hook that is called using "display_override"
   * directly before CI outputs information to the screen.
   * 
   * This function parses all <sourcecode>...</sourcecode> tags in the CI output and converts
   * them to GeSHi syntax-highlighted code
   * 
   * @access public
   * @param array $params
   */
	function run_geshi_filter(array $params = array())
	{
	  //If line numbers is explicitely turned on
		if (in_array('line_numbers_on', $params))
			$this->line_numbers_on = TRUE;
			
		//If line numbers is explicitely turned off (this one wins, if both defined)
    if (in_array('line_numbers_off', $params))
      $this->line_numbers_on = FALSE;
		
    //Get the output from CI
		$ci_output = $this->ci->output->get_output();
		
		//If there are <sourcecode>..</sourcecode> tags, process them
		if (strpos($ci_output, "<sourcecode"))
		{
			//Tried to use REGEX, but there were bugs!  Arg!
			$begin_searching_at = 0;
			while (strpos($ci_output, "<sourcecode", $begin_searching_at))
			{
				$begin = strpos($ci_output, "<sourcecode", $begin_searching_at);
				$end = strpos($ci_output, "</sourcecode>", $begin_searching_at) + strlen("</sourcecode>");
				
				//Test
				$ci_output = substr($ci_output, 0, $begin) . @$this->_set_geshi_content(substr($ci_output, $begin, $end-$begin)) . substr($ci_output, $end);
				
				$begin_searching_at = $end;
			}
			
			echo $ci_output;
		}
		else
		  echo $ci_output;	
	}

	// ------------------------------------------------------------------------	
	
	/**
	 * Set GeSHi Content converts strings that consist of
	 * "<sourcecode language='something'> ... </sourcecode> to GeSHi-highlighted
	 * code.  Yes, this is where the magic happens.
	 *
	 * @param string $code_to_process
	 * @return string
	 */
	function _set_geshi_content(string $code_to_process)
	{		
	  //Try .. catch block ; this is why this class requires PHP v5.
		try
		{
			//Break it up into chunks
			$opening_tag = substr($code_to_process, 0, strpos($code_to_process, ">"));
			$closing_tag = substr($code_to_process, strpos($code_to_process,"</sourcecode>"));
				
			$inner_code = substr($code_to_process, strpos($code_to_process, ">")+1, strpos($code_to_process,"</sourcecode>") - (strpos($code_to_process, ">")+1));
						
			//Try to determine the language
			//
			if (strpos($opening_tag, "language='"))
			  $q = "'";
			elseif(strpos($opening_tag, 'language="'))
				$q = '"';
			else
				$language = "html";
				
			if (isset($q) && ! isset($language))
			{
				$language_start = strpos($opening_tag, "language=$q") + strlen("language=$q");
				$language_end = strpos($opening_tag, $q, $language_start+1);
				
				$language = substr($opening_tag, $language_start, $language_end - $language_start);
			}
		
			//Run GeSHi on the inner code
			$geshi = new GeSHi($inner_code, $language);
			$geshi->set_overall_class('geshi');
				
			//If line numbers on
			if ($this->line_numbers_on)
			  $geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS, 1);
			
			//Return the output
			return $geshi->parse_code();
			
		}
		catch (Exception $e)
		{
		  //If we could not highlight the code,
		  //then just output it
			return $code_to_process;
		}
	}
	
}